﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using Kotonoha.Objects;
using Kotonoha.Server.Db.Dao;
using Kotonoha.Server.Objects.Model;
using Kotonoha.Server.Core.Utils;
using Kotonoha.Server.Dictionaries;
using Kotonoha.Server.Model;
using Kotonoha.Server.Plugins;
using Kotonoha.Server.UI.BadCards;
using Kotonoha.Server.UI.Comparators;
using Kotonoha.Server.UI.Model;
using Kotonoha.Server.UI.Resolver;
using Kotonoha.Server.UI.Settings;
using Kotonoha.Server.UI.Synch;
using Microsoft.Win32;
using System.Windows.Controls;
using NHibernate;

namespace Kotonoha.Server.UI {
    /// <summary>
    /// Interaction logic for KotonohaMain.xaml
    /// </summary>
    public partial class KotonohaMain : Window {
        private WordHolder words;
        private WordFiller filler;
        private ListCollectionView view;

        public KotonohaMain() {
            InitializeComponent();
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e) {
            SettingsForm form = new SettingsForm();
            form.Show();
        }

        private void KotonohaMain_OnInitialized(object sender, EventArgs e) {
            PluginManager manager = PluginManager.Instance;
            manager.Load(new DirectoryInfo("./Plugins"));
            /*if (!ResourceManager.Instance.Configure()) {
                SettingsForm form = new SettingsForm();
                form.ShowDialog();
                if (!ResourceManager.Instance.Configure()) {
                    Application.Current.Shutdown(1);
                }
            }*/

            filler = new WordFiller();
            words = new WordHolder();
            refreshList();
        }

        private void refreshList() {
            view = (ListCollectionView) CollectionViewSource.GetDefaultView(words.Collection);
            wordList.ItemsSource = view;
        }

        private void AddWord_Click(object sender, RoutedEventArgs e) {
            string s = SearchBox.Text;
            if (!string.IsNullOrEmpty(s)) {
                IList<WordEntry> found = new DictDao(HibernateUtil.Dictionary.Session).findWordByWriting(s);
                IList<WordEntry> resolved;
                if (found.Count == 0) {
                    Word w = new Word();
                    w.Translations.Add("");
                    w.Writing = s;
                    WordForm form = new WordForm();
                    form.DataContext = w;
                    if (form.ShowDialog() ?? false) {
                        WordFiller.fillCommonInWord(w);
                        addWord(w);
                    }
                }
                if (found.Count > 1) {
                    WordResolver resolver = new WordResolver();
                    resolver.DataContext = found;
                    resolver.ShowDialog();
                    resolved = resolver.ResolvedWords;
                } else {
                    resolved = found;
                }
                foreach (var entry in resolved) {
                    Word w;
                    if (filler.fill(entry, s, out w)) {
                        addWord(w);
                    }
                }
            }
        }

        private void addWord(Word w) {
            if (!words.ExistWithWriting(w)) {
                words.Save(w);
                ISession session = HibernateUtil.Model.Session;
                ITransaction transaction = session.BeginTransaction();
                try {
                    foreach (string s in KanjiFactory.enumerateKanji(w.Writing)) {
                        if (!new ModelDao(HibernateUtil.Model.Session).existKanji(s)) {
                            Kanji kanji = KanjiFactory.create(s);
                            session.Save(kanji);
                        }
                    }
                    transaction.Commit();
                } catch {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        private void KotonohaMain_Closed(object sender, EventArgs e) {}

        private void SynchItem_Click(object sender, RoutedEventArgs e) {
            SynchForm form = new SynchForm();
            form.Words = words;
            form.ShowDialog();
            wordList.Items.Refresh();
        }

        private void ImportItem_Click(object sender, RoutedEventArgs e) {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "CSV files|*.csv";
            bool? result = dialog.ShowDialog(this);
            if (result ?? false) {
                CSVReader reader = new CSVReader(File.OpenRead(dialog.FileName), Encoding.UTF8);
                ISession session = HibernateUtil.Model.Session;
                ModelDao dao = new ModelDao(session);
                ITransaction transaction = session.BeginTransaction();
                try {
                    List<Word> allWords = reader.ToList();
                    List<string> allKanji = allWords.SelectMany(w => KanjiFactory.enumerateKanji(w.Writing)).Distinct().ToList();

                    words.Save(false, allWords.Where(w => !words.ExistWithWriting(w)).ToArray());

                    HashSet<string> existKanji = new HashSet<string>(dao.findAllKanji(allKanji).Select(k => k.Character));

                    IEnumerable<Kanji> enumerable = allKanji.Where(s => !existKanji.Contains(s))
                        .Select(s => KanjiFactory.create(s));

                    foreach (var kanji in enumerable) {
                        session.Save(kanji);
                    }


                    transaction.Commit();
                } catch {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        private void BadCards_OnClick(object sender, RoutedEventArgs e) {
            BadCardsForm form = new BadCardsForm();
            form.ShowDialog();
        }

        private void DeleteWord_Click(object sender, RoutedEventArgs e) {
            IList items = wordList.SelectedItems;
            words.Delete(items.Cast<Word>().ToArray());
        }

        private readonly ComparatorFactory<Word> compFact = new ComparatorFactory<Word>();

        private string lastSort;
        private void WordList_OnSorting(object sender, DataGridSortingEventArgs e) {
            e.Handled = true;
            string path = e.Column.SortMemberPath;
            bool rev = Equals(path, lastSort);
            MasterComparator<Word> comparator = compFact.CreateComparersFor(rev, path);
            view.CustomSort = comparator;
            lastSort = rev ? null : path;
            e.Column.SortDirection = rev ? ListSortDirection.Ascending : ListSortDirection.Descending;
        }

        private void SearchBox_KeyDown(object sender, KeyEventArgs e) {
            if (e.Key == Key.Return) {
                AddWord_Click(sender, e);
                SearchBox.SelectionStart = 0;
                SearchBox.SelectionLength = SearchBox.Text.Length;
            }
        }

        private void WordList_OnMouseDoubleClick(object sender, MouseButtonEventArgs e) {
            WordForm form = new WordForm();
            object o = wordList.SelectedItem;
            form.DataContext = o;
            bool? dialog = form.ShowDialog();
            bool val = dialog ?? false;
            ISession s = HibernateUtil.Model.Session;
            if (val) {
                words.Update((Word)o);
            } else {
                s.Refresh(o);
            }
        }

        private void SearchBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) {
            wordList.Items.Filter = delegate(object o) {
                                        var w = (Word) o;
                                        if (w == null) {
                                            return false;
                                        }
                                        string value = SearchBox.Text;
                                        return w.Reading.StartsWith(value) || w.Writing.StartsWith(value);
                                    };
        }

    }
}